#ifndef __MY_SESSION_H__
#define __MY_SESSION_H__
#include "Util.hpp"

class Session
{
public:
    // // Session状态
    // enum SessionStatus
    // {
    //     LoggedOut = 0,
    //     LoggedIn = 1
    // };
    // 网站的所有操作都是在登录的前提下完成的，所以决定把状态去掉
    Session(id_t ssid, id_t uid) : _ssid(ssid), _uid(uid)
    {
        LOG(LogLevel::INFO) << "用户[uid=" << _uid << "]的会话创建成功!";
    }
    void SetUser(id_t uid) { _uid = uid; }
    id_t GetUser() { return _uid; }
    id_t GetId() { return _ssid; }
    void SetTimer(const ws_server_t::timer_ptr &tp) { _tp = tp; }
    ws_server_t::timer_ptr &GetTimer() { return _tp; }
    ~Session()
    {
        LOG(LogLevel::INFO) << "用户[uid=" << _uid << "]的会话即将销毁!";
    }

private:
    id_t _ssid; // 会话id
    id_t _uid;  // 该会话所属用户的uid
    ws_server_t::timer_ptr _tp;
};

using SessionPtr = std::shared_ptr<Session>;

class SessionManager
{
public:
    SessionManager(ws_server_t *server)
        : _server(server)
    {
        LOG(LogLevel::INFO) << "会话管理器创建成功!";
    }
    // 新建会话
    SessionPtr CreateSession(id_t uid)
    {
        std::unique_lock<std::mutex> lockguard(_mtx);
        SessionPtr ssp(new Session(_next_ssid++, uid));
        _ssid_sp[ssp->GetId()] = ssp;
        return ssp;
    }
    // 添加会话
    void AppendSession(const SessionPtr &ssp)
    {
        std::unique_lock<std::mutex> lockguard(_mtx);
        _ssid_sp[ssp->GetId()] = ssp;
    }
    // 获取会话
    SessionPtr GetSession(id_t ssid)
    {
        std::unique_lock<std::mutex> lockguard(_mtx);
        auto it = _ssid_sp.find(ssid);
        if (it == _ssid_sp.end())
        {
            return SessionPtr();
        }
        return it->second;
    }

    static const int TIMEOUT = 30000;
    static const int FOREVER = -1;
    void SetSessionExpireTime(id_t ssid, int ms)
    {
        // 依赖于websocketpp的定时器来管理会话的生命周期
        // 登录之后，在SESSION_TIMEOUT时间内无通信则删除会话
        // 进入游戏大厅或房间之后，会话永久不过期
        // 退出游戏大厅或房间之后，会话会话需要设置过期时间
        SessionPtr ssp = GetSession(ssid);
        if (ssp.get() == nullptr)
        {
            return;
        }

        ws_server_t::timer_ptr tp = ssp->GetTimer();
        if (tp.get() == nullptr && ms == FOREVER)
        {
            // 1.为永久会话设置永久，无意义，直接返回
            return;
        }
        else if (tp.get() == nullptr && ms != FOREVER)
        {
            // 2.为永久会话设置指定时间后删除
            ws_server_t::timer_ptr tp = _server->set_timer(ms, std::bind(&SessionManager::RemoveSession, this, ssid));
            ssp->SetTimer(tp);
        }
        else if (tp.get() != nullptr && ms == FOREVER)
        {
            // 3.为临时会话设置永久
            // 该函数实际上是立即触发回调
            tp->cancel();
            // 将目标会话的定时器指针置空
            ssp->SetTimer(ws_server_t::timer_ptr());
            // tp->cancel()立即触发但不立即执行，直接将ssp添加回去可能被后执行的回调函数删除
            // 所以应该为添加ssp的任务设置一个立即触发的定时器，使其加入到回调函数的执行队列中，确保在删除后再添加
            _server->set_timer(0, std::bind(&SessionManager::AppendSession, this, ssp));
        }
        else
        {
            // 4.为临时会话重新设置定时器
            // 清理旧定时器（同3）
            tp->cancel();
            _server->set_timer(0, std::bind(&SessionManager::AppendSession, this, ssp));

            // 设置新定时器（同2）
            ws_server_t::timer_ptr tp = _server->set_timer(ms, std::bind(&SessionManager::RemoveSession, this, ssid));
            ssp->SetTimer(tp);
        }
    }

    void RemoveSession(id_t ssid)
    {
        std::unique_lock<std::mutex> lockguard(_mtx);
        _ssid_sp.erase(ssid);
    }
    ~SessionManager()
    {
        LOG(LogLevel::INFO) << "会话管理器即将销毁!";
    }

private:
    id_t _next_ssid = 0;
    std::mutex _mtx;
    std::unordered_map<id_t, SessionPtr> _ssid_sp;
    ws_server_t *_server;
};

#endif